home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / samba.idb / usr / samba / src / source / mangle.c.z / mangle.c
Encoding:
C/C++ Source or Header  |  1998-10-28  |  19.2 KB  |  709 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Name mangling
  5.    Copyright (C) Andrew Tridgell 1992-1998
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #include "includes.h"
  23.  
  24. extern int DEBUGLEVEL;
  25. extern int case_default;
  26. extern BOOL case_mangle;
  27.  
  28. /****************************************************************************
  29.  * Provide a checksum on a string
  30.  *
  31.  *  Input:  s - the nul-terminated character string for which the checksum
  32.  *              will be calculated.
  33.  *  Output: The checksum value calculated for s.
  34.  *
  35.  ****************************************************************************/
  36. int str_checksum(char *s)
  37.   {
  38.   int res = 0;
  39.   int c;
  40.   int i=0;
  41.  
  42.   while( *s )
  43.     {
  44.     c = *s;
  45.     res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
  46.     s++; i++;
  47.     }
  48.   return(res);
  49.   } /* str_checksum */
  50.  
  51. /****************************************************************************
  52. return True if a name is a special msdos reserved name
  53. ****************************************************************************/
  54. static BOOL is_reserved_msdos(char *fname)
  55.   {
  56.   char upperFname[13];
  57.   char *p;
  58.  
  59.   StrnCpy (upperFname, fname, 12);
  60.  
  61.   /* lpt1.txt and con.txt etc are also illegal */
  62.   p=strchr(upperFname,'.');
  63.   if (p)
  64.    *p='\0';
  65.   strupper (upperFname);
  66.   if ((strcmp(upperFname,"CLOCK$") == 0) ||
  67.     (strcmp(upperFname,"CON") == 0) ||
  68.     (strcmp(upperFname,"AUX") == 0) ||
  69.     (strcmp(upperFname,"COM1") == 0) ||
  70.     (strcmp(upperFname,"COM2") == 0) ||
  71.     (strcmp(upperFname,"COM3") == 0) ||
  72.     (strcmp(upperFname,"COM4") == 0) ||
  73.     (strcmp(upperFname,"LPT1") == 0) ||
  74.     (strcmp(upperFname,"LPT2") == 0) ||
  75.     (strcmp(upperFname,"LPT3") == 0) ||
  76.     (strcmp(upperFname,"NUL") == 0) ||
  77.     (strcmp(upperFname,"PRN") == 0))
  78.       return (True) ;
  79.  
  80.   return (False);
  81.   } /* is_reserved_msdos */
  82.  
  83.  
  84.  
  85. /****************************************************************************
  86. return True if a name is in 8.3 dos format
  87. ****************************************************************************/
  88. BOOL is_8_3(char *fname, BOOL check_case)
  89.   {
  90.   int len;
  91.   char *dot_pos;
  92.   char *slash_pos = strrchr(fname,'/');
  93.   int l;
  94.  
  95.   if( slash_pos )
  96.     fname = slash_pos+1;
  97.   len = strlen(fname);
  98.  
  99.   DEBUG(5,("checking %s for 8.3\n",fname));
  100.  
  101.   if( check_case && case_mangle )
  102.     {
  103.     switch (case_default)
  104.       {
  105.       case CASE_LOWER:
  106.         if (strhasupper(fname)) return(False);
  107.         break;
  108.       case CASE_UPPER:
  109.         if (strhaslower(fname)) return(False);
  110.         break;
  111.       }
  112.     }
  113.  
  114.   /* can't be longer than 12 chars */
  115.   if( len == 0 || len > 12 )
  116.     return(False);
  117.  
  118.   /* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
  119.   if( is_reserved_msdos(fname) )
  120.     return(False);
  121.  
  122.   /* can't contain invalid dos chars */
  123.   /* Windows use the ANSI charset.
  124.      But filenames are translated in the PC charset.
  125.      This Translation may be more or less relaxed depending
  126.      the Windows application. */
  127.  
  128.   /* %%% A nice improvment to name mangling would be to translate
  129.      filename to ANSI charset on the smb server host */
  130.  
  131.   dot_pos = strchr(fname,'.');
  132.  
  133.   {
  134.     char *p = fname;
  135.     int skip;
  136.  
  137.     dot_pos = 0;
  138.     while (*p)
  139.     {
  140.       if((skip = skip_multibyte_char( *p )) != 0)
  141.         p += skip;
  142.       else 
  143.       {
  144.         if (*p == '.' && !dot_pos)
  145.           dot_pos = (char *) p;
  146.         if (!isdoschar(*p))
  147.           return(False);
  148.         p++;
  149.       }
  150.     }
  151.   }      
  152.  
  153.   /* no dot and less than 9 means OK */
  154.   if (!dot_pos)
  155.     return(len <= 8);
  156.         
  157.   l = PTR_DIFF(dot_pos,fname);
  158.  
  159.   /* base must be at least 1 char except special cases . and .. */
  160.   if( l == 0 )
  161.     return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0);
  162.  
  163.   /* base can't be greater than 8 */
  164.   if( l > 8 )
  165.     return(False);
  166.  
  167.   if( lp_strip_dot() && 
  168.       len - l == 1 &&
  169.       !strchr(dot_pos+1,'.') )
  170.     {
  171.     *dot_pos = 0;
  172.     return(True);
  173.     }
  174.  
  175.   /* extension must be between 1 and 3 */
  176.   if( (len - l < 2 ) || (len - l > 4) )
  177.     return(False);
  178.  
  179.   /* extension can't have a dot */
  180.   if( strchr(dot_pos+1,'.') )
  181.     return(False);
  182.  
  183.   /* must be in 8.3 format */
  184.   return(True);
  185.   } /* is_8_3 */
  186.  
  187. /* -------------------------------------------------------------------------- **
  188.  * This section creates and maintains a stack of name mangling results.
  189.  * The original comments read: "keep a stack of name mangling results - just
  190.  * so file moves and copies have a chance of working" (whatever that means).
  191.  *
  192.  * There are three functions to manage the stack:
  193.  *   reset_mangled_stack() -
  194.  *   push_mangled_name()    -
  195.  *   check_mangled_stack()  -
  196.  */
  197.  
  198. fstring *mangled_stack = NULL;
  199. int mangled_stack_size = 0;
  200. int mangled_stack_len = 0;
  201.  
  202. /****************************************************************************
  203.  * create the mangled stack CRH
  204.  ****************************************************************************/
  205. void reset_mangled_stack( int size )
  206.   {
  207.   if( mangled_stack )
  208.     {
  209.     free(mangled_stack);
  210.     mangled_stack_size = 0;
  211.     mangled_stack_len = 0;
  212.     }
  213.  
  214.   if( size > 0 )
  215.     {
  216.     mangled_stack = (fstring *)malloc( sizeof(fstring) * size );
  217.     if( mangled_stack )
  218.       mangled_stack_size = size;
  219.     }
  220.   else
  221.     mangled_stack = NULL;
  222.   } /* create_mangled_stack */
  223.  
  224. /****************************************************************************
  225.  * push a mangled name onto the stack CRH
  226.  ****************************************************************************/
  227. static void push_mangled_name(char *s)
  228.   {
  229.   int i;
  230.   char *p;
  231.  
  232.   /* If the stack doesn't exist... Fail. */
  233.   if( !mangled_stack )
  234.     return;
  235.  
  236.   /* If name <s> is already on the stack, move it to the top. */
  237.   for( i=0; i<mangled_stack_len; i++ )
  238.     {
  239.     if( strcmp( s, mangled_stack[i] ) == 0 )
  240.       {
  241.       array_promote( mangled_stack[0],sizeof(fstring), i );
  242.       return;
  243.       }
  244.     }
  245.  
  246.   /* If name <s> wasn't already there, add it to the top of the stack. */
  247.   memmove( mangled_stack[1], mangled_stack[0],
  248.            sizeof(fstring) * MIN(mangled_stack_len, mangled_stack_size-1) );
  249.   fstrcpy( mangled_stack[0], s );
  250.   mangled_stack_len = MIN( mangled_stack_size, mangled_stack_len+1 );
  251.  
  252.   /* Hmmm...
  253.    *  Find the last dot '.' in the name,
  254.    *  if there are any upper case characters past the last dot
  255.    *  and there are no more than three characters past the last dot
  256.    *  then terminate the name *at* the last dot.
  257.    */
  258.   p = strrchr( mangled_stack[0], '.' );
  259.   if( p && (!strhasupper(p+1)) && (strlen(p+1) < (size_t)4) )
  260.     *p = 0;
  261.  
  262.   } /* push_mangled_name */
  263.  
  264. /****************************************************************************
  265.  * check for a name on the mangled name stack CRH
  266.  ****************************************************************************/
  267. BOOL check_mangled_stack(char *s)
  268.   {
  269.   int i;
  270.   pstring tmpname;
  271.   char extension[5];
  272.   char *p              = strrchr( s, '.' );
  273.   BOOL check_extension = False;
  274.  
  275.   extension[0] = 0;
  276.  
  277.   /* If the stack doesn't exist, fail. */
  278.   if( !mangled_stack )
  279.     return(False);
  280.  
  281.   /* If there is a file extension, then we need to play with it, too. */
  282.   if( p )
  283.     {
  284.     check_extension = True;
  285.     StrnCpy( extension, p, 4 );
  286.     strlower( extension ); /* XXXXXXX */
  287.     }
  288.  
  289.   for( i=0; i<mangled_stack_len; i++ )
  290.     {
  291.     pstrcpy(tmpname,mangled_stack[i]);
  292.     mangle_name_83(tmpname,sizeof(tmpname)-1);
  293.     if( strequal(tmpname,s) )
  294.       {
  295.       fstrcpy(s,mangled_stack[i]);
  296.       break;
  297.       }
  298.     if( check_extension && !strchr(mangled_stack[i],'.') )
  299.       {
  300.       pstrcpy(tmpname,mangled_stack[i]);
  301.       pstrcat(tmpname,extension);
  302.       mangle_name_83(tmpname, sizeof(tmpname)-1);
  303.       if( strequal(tmpname,s) )
  304.         {
  305.         fstrcpy(s,mangled_stack[i]);
  306.         fstrcat(s,extension);
  307.         break;
  308.         }          
  309.       }
  310.     }
  311.  
  312.   if( i < mangled_stack_len )
  313.     {
  314.     DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i]));
  315.     array_promote(mangled_stack[0],sizeof(fstring),i);
  316.     return(True);      
  317.     }
  318.  
  319.   return(False);
  320.   } /* check_mangled_stack */
  321.  
  322.  
  323. /* End of the mangled stack section.
  324.  * -------------------------------------------------------------------------- **
  325.  */
  326.  
  327.  
  328. static char *map_filename( char *s,         /* This is null terminated */
  329.                            char *pattern,   /* This isn't. */
  330.                            int len )        /* This is the length of pattern. */
  331.   {
  332.   static pstring matching_bit;  /* The bit of the string which matches */
  333.                                 /* a * in pattern if indeed there is a * */
  334.   char *sp;                     /* Pointer into s. */
  335.   char *pp;                     /* Pointer into p. */
  336.   char *match_start;            /* Where the matching bit starts. */
  337.   pstring pat;
  338.  
  339.   StrnCpy(pat, pattern, len);   /* Get pattern into a proper string! */
  340.   pstrcpy(matching_bit,"");     /* Match but no star gets this. */
  341.   pp = pat;                     /* Initialise the pointers. */
  342.   sp = s;
  343.   if( (len == 1) && (*pattern == '*') )
  344.     {
  345.     return NULL;                /* Impossible, too ambiguous for */
  346.     }                           /* words! */
  347.  
  348.   while ((*sp)                  /* Not the end of the string. */
  349.          && (*pp)               /* Not the end of the pattern. */
  350.          && (*sp == *pp)        /* The two match. */
  351.          && (*pp != '*'))       /* No wildcard. */
  352.     {
  353.     sp++;                       /* Keep looking. */
  354.     pp++;
  355.     }
  356.  
  357.   if( !*sp && !*pp )            /* End of pattern. */
  358.     return( matching_bit );     /* Simple match.  Return empty string. */
  359.  
  360.   if (*pp == '*')
  361.     {
  362.     pp++;                       /* Always interrested in the chacter */
  363.                                 /* after the '*' */
  364.     if (!*pp)                   /* It is at the end of the pattern. */
  365.       {
  366.       StrnCpy(matching_bit, s, sp-s);
  367.       return matching_bit;
  368.       }
  369.     else
  370.       {
  371.       /* The next character in pattern must match a character further */
  372.       /* along s than sp so look for that character. */
  373.       match_start = sp;
  374.       while( (*sp)              /* Not the end of s. */
  375.              && (*sp != *pp))   /* Not the same  */
  376.         sp++;                   /* Keep looking. */
  377.       if (!*sp)                 /* Got to the end without a match. */
  378.         {
  379.         return NULL;
  380.         }                       /* Still hope for a match. */
  381.       else
  382.         {
  383.         /* Now sp should point to a matching character. */
  384.         StrnCpy(matching_bit, match_start, sp-match_start);
  385.         /* Back to needing a stright match again. */
  386.         while( (*sp)            /* Not the end of the string. */
  387.                && (*pp)         /* Not the end of the pattern. */
  388.                && (*sp == *pp) ) /* The two match. */
  389.           {
  390.           sp++;                 /* Keep looking. */
  391.           pp++;
  392.           }
  393.         if (!*sp && !*pp)       /* Both at end so it matched */
  394.           return matching_bit;
  395.         else
  396.           return NULL;
  397.         }
  398.       }
  399.     }
  400.   return NULL;                  /* No match. */
  401.   } /* map_filename */
  402.  
  403.  
  404. /* this is the magic char used for mangling */
  405. char magic_char = '~';
  406.  
  407.  
  408. /****************************************************************************
  409. return True if the name could be a mangled name
  410. ****************************************************************************/
  411. BOOL is_mangled( char *s )
  412.   {
  413.   char *m = strchr(s,magic_char);
  414.  
  415.   if( !m )
  416.     return(False);
  417.  
  418.   /* we use two base 36 chars before the extension */
  419.   if( m[1] == '.' || m[1] == 0 ||
  420.       m[2] == '.' || m[2] == 0 ||
  421.       (m[3] != '.' && m[3] != 0) )
  422.     return( is_mangled(m+1) );
  423.  
  424.   /* it could be */
  425.   return(True);
  426.   } /* is_mangled */
  427.  
  428.  
  429.  
  430. /****************************************************************************
  431. return a base 36 character. v must be from 0 to 35.
  432. ****************************************************************************/
  433. static char base36(unsigned int v)
  434.   {
  435.   static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  436.   return basechars[v % 36];
  437.   } /* base36 */
  438.  
  439.  
  440. static void do_fwd_mangled_map(char *s, char *MangledMap)
  441.   {
  442.   /* MangledMap is a series of name pairs in () separated by spaces.
  443.    * If s matches the first of the pair then the name given is the
  444.    * second of the pair.  A * means any number of any character and if
  445.    * present in the second of the pair as well as the first the
  446.    * matching part of the first string takes the place of the * in the
  447.    * second.
  448.    *
  449.    * I wanted this so that we could have RCS files which can be used
  450.    * by UNIX and DOS programs.  My mapping string is (RCS rcs) which
  451.    * converts the UNIX RCS file subdirectory to lowercase thus
  452.    * preventing mangling.
  453.    */
  454.   char *start=MangledMap;       /* Use this to search for mappings. */
  455.   char *end;                    /* Used to find the end of strings. */
  456.   char *match_string;
  457.   pstring new_string;           /* Make up the result here. */
  458.   char *np;                     /* Points into new_string. */
  459.  
  460.   DEBUG(5,("Mangled Mapping '%s' map '%s'\n", s, MangledMap));
  461.   while (*start)
  462.     {
  463.     while ((*start) && (*start != '('))
  464.       start++;
  465.     if (!*start)
  466.       continue;                 /* Always check for the end. */
  467.     start++;                    /* Skip the ( */
  468.     end = start;                /* Search for the ' ' or a ')' */
  469.     DEBUG(5,("Start of first in pair '%s'\n", start));
  470.     while ((*end) && !((*end == ' ') || (*end == ')')))
  471.       end++;
  472.     if (!*end)
  473.       {
  474.       start = end;
  475.       continue;                 /* Always check for the end. */
  476.       }
  477.     DEBUG(5,("End of first in pair '%s'\n", end));
  478.     if ((match_string = map_filename(s, start, end-start)))
  479.       {
  480.       DEBUG(5,("Found a match\n"));
  481.       /* Found a match. */
  482.       start = end+1;            /* Point to start of what it is to become. */
  483.       DEBUG(5,("Start of second in pair '%s'\n", start));
  484.       end = start;
  485.       np = new_string;
  486.       while ((*end)             /* Not the end of string. */
  487.              && (*end != ')')   /* Not the end of the pattern. */
  488.              && (*end != '*'))  /* Not a wildcard. */
  489.         *np++ = *end++;
  490.       if (!*end)
  491.         {
  492.         start = end;
  493.         continue;               /* Always check for the end. */
  494.         }
  495.       if (*end == '*')
  496.         {
  497.         pstrcpy(np, match_string);
  498.         np += strlen(match_string);
  499.         end++;                  /* Skip the '*' */
  500.         while ((*end)             /* Not the end of string. */
  501.                && (*end != ')')   /* Not the end of the pattern. */
  502.                && (*end != '*'))  /* Not a wildcard. */
  503.           *np++ = *end++;
  504.         }
  505.       if (!*end)
  506.         {
  507.         start = end;
  508.         continue;               /* Always check for the end. */
  509.         }
  510.       *np++ = '\0';             /* NULL terminate it. */
  511.       DEBUG(5,("End of second in pair '%s'\n", end));
  512.       pstrcpy(s, new_string);    /* Substitute with the new name. */
  513.       DEBUG(5,("s is now '%s'\n", s));
  514.       }
  515.     start = end;              /* Skip a bit which cannot be wanted */
  516.     /* anymore. */
  517.     start++;
  518.     }
  519.   } /* do_fwd_mangled_map */
  520.  
  521. /****************************************************************************
  522. do the actual mangling to 8.3 format
  523. ****************************************************************************/
  524. void mangle_name_83(char *s, int s_len)
  525.   {
  526.   int csum = str_checksum(s);
  527.   char *p;
  528.   char extension[4];
  529.   char base[9];
  530.   int baselen = 0;
  531.   int extlen = 0;
  532.   int skip;
  533.  
  534.   extension[0]=0;
  535.   base[0]=0;
  536.  
  537.   p = strrchr(s,'.');  
  538.   if( p && (strlen(p+1) < (size_t)4) )
  539.     {
  540.     BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
  541.  
  542.     if (all_normal && p[1] != 0)
  543.       {
  544.       *p = 0;
  545.       csum = str_checksum(s);
  546.         *p = '.';
  547.       }
  548.     }
  549.  
  550.   strupper(s);
  551.  
  552.   DEBUG(5,("Mangling name %s to ",s));
  553.  
  554.   if( p )
  555.     {
  556.     if (p == s)
  557.       fstrcpy(extension,"___");
  558.     else
  559.       {
  560.       *p++ = 0;
  561.       while (*p && extlen < 3)
  562.         {
  563.         skip = skip_multibyte_char(*p);
  564.         if (skip == 2)
  565.           {
  566.           if (extlen < 2)
  567.             {
  568.             extension[extlen++] = p[0];
  569.             extension[extlen++] = p[1];
  570.             }
  571.           else 
  572.             {
  573.             extension[extlen++] = base36 (((unsigned char) *p) % 36);
  574.             }
  575.           p += 2;
  576.           }
  577.         else if( skip == 1 )
  578.           {
  579.           extension[extlen++] = p[0];
  580.           p++;
  581.           }
  582.         else 
  583.           {
  584.           if (isdoschar (*p) && *p != '.')
  585.             extension[extlen++] = p[0];
  586.           p++;
  587.           }
  588.         }
  589.       extension[extlen] = 0;
  590.       }
  591.     }
  592.  
  593.   p = s;
  594.  
  595.   while (*p && baselen < 5)
  596.     {
  597.       skip = skip_multibyte_char(*p);
  598.       if (skip == 2)
  599.         {
  600.         if (baselen < 4)
  601.           {
  602.           base[baselen++] = p[0];
  603.           base[baselen++] = p[1];
  604.           }
  605.         else 
  606.           {
  607.           base[baselen++] = base36 (((unsigned char) *p) % 36);
  608.           }
  609.         p += 2;
  610.         }
  611.       else if( skip == 1)
  612.         {
  613.         base[baselen++] = p[0];
  614.         p++;
  615.         }
  616.       else 
  617.         {
  618.         if (isdoschar (*p) && *p != '.')
  619.           base[baselen++] = p[0];
  620.         p++;
  621.         }
  622.     }
  623.   base[baselen] = 0;
  624.  
  625.   csum = csum % (36*36);
  626.  
  627.   slprintf(s, s_len - 1, "%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36));
  628.  
  629.   if( *extension )
  630.     {
  631.     fstrcat(s,".");
  632.     fstrcat(s,extension);
  633.     }
  634.   DEBUG(5,("%s\n",s));
  635.  
  636.   } /* mangle_name_83 */
  637.  
  638.  
  639.  
  640. /*******************************************************************
  641.   work out if a name is illegal, even for long names
  642.   ******************************************************************/
  643. static BOOL illegal_name(char *name)
  644.   {
  645.   static unsigned char illegal[256];
  646.   static BOOL initialised=False;
  647.   unsigned char *s;
  648.   int skip;
  649.  
  650.   if( !initialised )
  651.     {
  652.     char *ill = "*\\/?<>|\":";
  653.     initialised = True;
  654.   
  655.     bzero((char *)illegal,256);
  656.     for( s = (unsigned char *)ill; *s; s++ )
  657.       illegal[*s] = True;
  658.     }
  659.  
  660.   for (s = (unsigned char *)name; *s;)
  661.     {
  662.     skip = skip_multibyte_char( *s );
  663.     if (skip != 0)
  664.       s += skip;
  665.     else
  666.       {
  667.       if (illegal[*s])
  668.         return(True);
  669.       else
  670.         s++;
  671.       }
  672.     }
  673.  
  674.   return(False);
  675.   } /* illegal_name */
  676.  
  677.  
  678. /****************************************************************************
  679. convert a filename to DOS format. return True if successful.
  680. ****************************************************************************/
  681. BOOL name_map_mangle(char *OutName,BOOL need83,int snum)
  682.   {
  683. #ifdef MANGLE_LONG_FILENAMES
  684.   if( !need83 && illegal_name(OutName) )
  685.     need83 = True;
  686. #endif  
  687.  
  688.   /* apply any name mappings */
  689.   {
  690.   char *map = lp_mangled_map(snum);
  691.  
  692.   if (map && *map)
  693.     do_fwd_mangled_map(OutName,map);
  694.   }
  695.  
  696.   /* check if it's already in 8.3 format */
  697.   if( need83 && !is_8_3(OutName, True) )
  698.     {
  699.     if( !lp_manglednames(snum) )
  700.       return(False);
  701.  
  702.     /* mangle it into 8.3 */
  703.     push_mangled_name(OutName);  
  704.     mangle_name_83(OutName,sizeof(pstring)-1);
  705.     }
  706.   
  707.   return(True);
  708.   } /* name_map_mangle */
  709.